﻿//  Copyright (c) 2009 Ray Liang (http://www.dotnetage.com)
//  Dual licensed under the MIT and GPL licenses:
//  http://www.opensource.org/licenses/mit-license.php
//  http://www.gnu.org/licenses/gpl.html

using System;
using System.Collections.Generic;
using System.Web.Mvc;
using System.Web.Security;
using DNA.Mvc.Controllers;
using DNA.Mvc.Publishing;
using DNA.Mvc.UI;
using DNA.OpenAPI.Atom;
using DNA.OpenAPI.Rss;
using DNA.Utility;
using DNA.Mvc.Text;

namespace DNA.Mvc.Publishing.Controllers
{
    public class CategoryController : Controller
    {
        private IPubContext pubContext;

        public CategoryController(IPubContext _context)
        {
            pubContext = _context;
        }

        //private IEnumerable<Category> _GetCategories(int id)
        //{
        //    throw new NotImplementedException();
        //}

        private Category _Find(int id)
        {
            return pubContext.Categories.Find(id);
        }

        private CategoryWrapper _Wrap(int id)
        {
            return new CategoryWrapper(_Find(id));
        }

        private Category _GetDefault(IDictionary<string, object> values)
        {
            var name = values.ContainsKey("website") ? values["website"].ToString() : "home";
            return pubContext.Categories.Find(name);
        }

        private Category _Update(Category category)
        {
            if (category.ID == 0)
            {
                category.LastPosted = new DateTime(1800, 1, 1);
                pubContext.Categories.Create(category);
            }
            else
            {
                pubContext.Categories.Update(category);
            }

            pubContext.SaveChanges();
            return category;
        }

        private void _Delete(int id)
        {
            var cat = _Find(id);
            pubContext.Categories.Delete(cat);
            pubContext.SaveChanges();
        }

        [SecurityAction("Publishing", "Edit category", "Can shows the  category editing ui to users. ",
            TitleResName = "SA_EditCat",
            DescResName = "SA_EditCatDesc",
            PermssionSetResName = "SA_Publishing"
            )]
        public ActionResult Edit(int id)
        {
            return PartialView(_Find(id));
        }

        [SecurityAction("Publishing", "Edit category", "Can shows the  category editing ui to users. ",
            TitleResName = "SA_EditCat",
            DescResName = "SA_EditCatDesc",
            PermssionSetResName = "SA_Publishing"
            )]
        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Edit(int id, FormCollection forms)
        {
            var cat = _Find(id);
            if (TryUpdateModel<Category>(cat, "Category"))
            {
                if ((cat.Title.Equals("{blogs}", StringComparison.OrdinalIgnoreCase)) || (cat.Title.Equals("{site}", StringComparison.OrdinalIgnoreCase)))
                {
                    ModelState.AddModelError("", "Could not accept your category title.");
                    return View(cat);
                }
                _Update(cat);
            }
            return View(cat);
        }

        [SecurityAction("Publishing", "Delete category", "Allows user can delete the categories.",
            TitleResName = "SA_DeleteCat",
            DescResName = "SA_DeleteCatDesc",
            PermssionSetResName = "SA_Publishing"
            )]
        [HttpPost]
        public void Delete(int id)
        {
            if (id == 0)
                throw new ArgumentOutOfRangeException("id");

            _Delete(id);
        }

        [SecurityAction("Publishing", "Create category", "Allows user create new category.",
            TitleResName = "SA_CreateCategory",
            DescResName = "SA_CreateCategoryDesc",
            PermssionSetResName = "SA_Publishing"
            )]
        public ActionResult Create(int id)
        {
            return View(_Find(id));
        }

        [HttpPost]
        [ValidateAntiForgeryToken]
        [SecurityAction("Publishing", "Create category", "Allows user create new category.",
            TitleResName = "SA_CreateCategory",
            DescResName = "SA_CreateCategoryDesc",
            PermssionSetResName = "SA_Publishing"
            )]
        public ActionResult Create(int id, [Bind(Prefix = "Category")] Category cat)
        {
            if ((cat.Title.Equals("{blogs}", StringComparison.OrdinalIgnoreCase)) || (cat.Title.Equals("{site}", StringComparison.OrdinalIgnoreCase)))
                ModelState.AddModelError("", "Could not accept your category title.");


            if (ModelState.IsValid)
            {
                var parentCategory = _Find(id);

                cat.IsModerated = false;
                cat.LastPosted = new DateTime(1800, 1, 1);
                cat.Path = (parentCategory.Path + "/" + TextUtility.Slug(cat.Title)).ToLower();
                cat.ParentID = id;

                _Update(cat);
                return View("CreateSuccess", cat);
            }
            return View(cat);
        }

        [HttpPost]
        public int Add(int id, string title)
        {
            if (!HttpContext.Request.IsAuthenticated)
                throw new UnauthorizedAccessException();

            //var web = this.CurrentWeb();

            //if (web.IsRoot)
            //{
            //    if (!this.IsAuthorize("Create"))
            //        throw new UnauthorizedAccessException(Resources.language.AccessDenied_MSG);
            //}
            //else
            //    if (!User.IsWebOwner()) throw new UnauthorizedAccessException(Resources.language.AccessDenied_MSG);

            if (string.IsNullOrEmpty(title))
                throw new ArgumentNullException("title");

            var cat = _Find(id);// web.FindCategory(id);

            var newCat = new Category()
            {
                Title = title,
                //ArticleType = (int)(web.IsRoot ? ArticleTypes.Public : ArticleTypes.Personal),
                AllowAnonymousPostComment = false,
                IsModerated = false,
                LastPosted = new DateTime(1800, 1, 1),
                Path = (cat.Path + "/" + TextUtility.Slug(cat.Title)).ToLower(),
                ParentID = id //cat.ID
            };

            _Update(newCat);
            //cat.AddChildren(newCat);
            return newCat.ID;
        }

        public void Move(int id, int parentID, int pos)
        {
            if (id <= 0) throw new ArgumentOutOfRangeException("id");
            if (id == parentID) throw new ArgumentException("The parentID is point to itselft");

            pubContext.Categories.Move(parentID, id, pos);
            pubContext.SaveChanges();
        }

        [SiteControlPanel(Text = "Publishing", Order = 6, ResBaseName = "publishing", ResKey = "publishing", Group = "Content")]
        [MyControlPanel("Publishing", Order = 6, ResBaseName = "publishing", ResKey = "publishing", Group = "Content", ShowInPersonalSiteOnly = true)]
        [SecurityAction("Publishing", "Publishing Manager", "Allows user can use Publishing Manager.",
            TitleResName = "SA_PubMan",
            DescResName = "SA_PubManDesc",
            PermssionSetResName = "SA_Publishing"
            )]
        public ActionResult Settings()
        {
            ViewBag.Provider = new CategoryNodeProvider(pubContext.Categories);
            return View();
        }

        public ActionResult CatRoot()
        {
            //var web = WebSite.Open(RouteData);
            //if (web.Properties.ContainsKey("PublishingRoot"))
            //    ViewData["Root"] = web.Properties["PublishingRoot"];
            return View();
        }

        [OutputCache(Duration = 3600, VaryByParam = "*")]
        public ActionResult Rss(int id)
        {
            var category = _Wrap(id);

            var doc = new RssDocument();
            var channel = new RssChannel()
            {
                Title = category.Title,
                Description = category.Description,
                Link = "",
                Generator = "DotNetAge " + System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString()
            };

            var children = category.Articles;

            channel.Items = new List<RssItem>();
            foreach (var child in children)
            {
                var article = new ArticleWrapper(child);
                var content = article.GetGlobalizationContent();
                var _title = content.Title;
                var _summary = content.Summary;
                if (string.IsNullOrEmpty(_summary))
                {
                    if (article.ContentFormat == 2)
                    {
                        _summary = TextEngine.Text(TextEngine.Wiki(content.Body.Replace("{toc}", "")).ToString());
                    }
                    else
                    {
                        _summary = TextEngine.Text(content.Body);
                    }
                }
                if (!string.IsNullOrEmpty(_summary) && _summary.Length > 255)
                {
                    _summary = _summary.Substring(0, 255) + "...";
                }

                var item = new RssItem()
                {
                    Title = _title,
                    Author = article.Author.Email,
                    Description = _summary,
                    Link = article.PermaLink,
                    PubDate = article.Posted.ToUniversalTime().ToString("r")
                };

                if (!string.IsNullOrEmpty(article.ImageUrl))
                    item.Enclosure = new RssEnclosure()
                    {
                        ContentType = FileUtility.GetContentType(article.ImageUrl),
                        Url = article.ImageUrl
                    };
                channel.Items.Add(item);
            }
            doc.Channel = channel;

            string xml = XmlSerializerUtility.SerializeToXml<RssDocument>(doc);
            return Content(xml, "text/xml");
        }

        [OutputCache(Duration = 3600, VaryByParam = "*")]
        public ActionResult Atom(int id)
        {
            var cat = _Wrap(id);

            var feedBuilder = new AtomFeedBuilder(cat.Title, cat.Description, cat.PermaLink);
            feedBuilder.SetGenerator(UrlResolver.ApplicationPath,
                System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString(),
                "DotNetAge");

            if (!string.IsNullOrEmpty(cat.ImageUrl))
                feedBuilder.SetLogo(Url.Content(cat.ImageUrl));

            //if (cat.LastPosted>0)
            feedBuilder.SetLastUpdated(cat.LastPosted);

            var articles = cat.Articles;
            //feedBuilder.AddCategory(new AtomCategory() { Text = cat.Title, Term = cat.Title,Scheme=cat.PermaLink });

            feedBuilder.AddEntries(articles, (art, eb) =>
            {
                var _article = new ArticleWrapper(art);
                var content = _article.GetGlobalizationContent();
                var _title = content.Title;
                var _summary = content.Summary;
                if (string.IsNullOrEmpty(_summary))
                {
                    if (_article.ContentFormat == 2)
                    {
                        _summary = TextEngine.Text(TextEngine.Wiki(content.Body.Replace("{toc}", "")).ToString());
                    }
                    else
                    {
                        _summary = TextEngine.Text(content.Body);
                    }
                }
                if (!string.IsNullOrEmpty(_summary) && _summary.Length > 255)
                {
                    _summary = _summary.Substring(0, 255) + "...";
                }
                eb.SetBaseInfo(_article.PermaLink, _title, _article.Posted);
                eb.SetAuthor(_article.UserName, email: _article.Author.Email);
                eb.SetSummary(_summary);
                eb.AddLink(new AtomLink() { Text = _title, NavigateUrl = _article.PermaLink });
                eb.SetLastUpdated(_article.LastModified);

                var atomCats = new List<AtomCategory>();
                var cats = _article.AllCategories();// _GetCategories(_article.ID);

                foreach (var c in cats)
                {
                    var _cw = new CategoryWrapper(c);
                    atomCats.Add(new AtomCategory()
                    {
                        Text = _cw.Title,
                        Scheme = _cw.PermaLink,
                        Term = _cw.Title
                    });
                }
                eb.AddCategories(atomCats);
                //eb.SetContent(_article.Body);
            });

            string xml = XmlSerializerUtility.SerializeToXml<AtomFeed>(feedBuilder.GetAtomFeed());
            return Content(xml, "text/xml");
        }

        //public ActionResult Opml()
        //{
        //    var doc = this.CurrentWeb().GetOpmlDocument();
        //    string xml = DNA.Utility.XmlSerializerUtility.SerializeToXml(typeof(DNA.OpenAPI.Opml.OpmlDocument), doc);
        //    return Content(xml,"text/xml");
        //}

        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult CatRoot(string rootText)
        {
            //if (!string.IsNullOrEmpty(rootText))
            //{
            //    var web = this.CurrentWeb();
            //    if (!web.Properties.ContainsKey("PublishingRoot"))
            //        web.Properties.Add("PublishingRoot", rootText);
            //    else
            //        web.Properties["PublishingRoot"] = rootText;
            //    //WebSite.Update(web);
            //    web.Update();
            //    ViewData["Root"] = web.Properties["PublishingRoot"];
            //}
            return View();
        }

        [Widget("Category Tree", "Display all children categories in a tree",
            Category = "Publishing",
            ShowBorder = true,
            ShowHeader = true,
            ImageUrl = "~/Content/Images/Widgets/cat.png",
            IconUrl = "~/Content/Images/Widgets/cat_16.png"
            )]
        [Property("CategoryID", ValueType = typeof(int), DefaultValue = 0)]
        [Property("ShowAsMenu", ValueType = typeof(bool), DefaultValue = false)]
        public ActionResult CategoryNav(int categoryID)
        {
            _InitCatTreeWidgets(categoryID);
            return View();
        }

        [Widget("Category map", "Show all categories as a sitemap",
    Category = "Publishing",
    ShowBorder = true,
    ShowHeader = false
    )]
        [Property("CategoryID", ValueType = typeof(int), DefaultValue = 0)]
        [Property("Depth", ValueType = typeof(int), DefaultValue = 1)]
        [Property("Columns", ValueType = typeof(int), DefaultValue = 1)]
        [Property("ShowIcons", ValueType = typeof(bool), DefaultValue = false)]
        public ActionResult CategoryMap(int categoryID)
        {
            _InitCatTreeWidgets(categoryID);
            return View();
        }

        private void _InitCatTreeWidgets(int categoryID)
        {
            var cat = _Find(categoryID);
            if (cat != null)
                ViewData.Model = new CategoryWrapper(cat);
            else
                ViewData.Model = new CategoryWrapper(_GetDefault(RouteData.Values));

            ViewBag.Provider = new CategoryNodeProvider(pubContext.Categories);
        }

        //public ActionResult Export()
        //{
        //    var blog = new Blog(this.CurrentWeb().Name);
        //     return Content(blog.ExportToXml(),"text/xml");
        //}

        //public ActionResult Import()
        //{
        //    try
        //    {
        //        if (Request.Files.Count == 0)
        //        {
        //            HttpContext.Response.StatusCode = 204;
        //            return Content(Resources.publishing.NoContent);
        //        }
        //        var blog = new Blog(this.CurrentWeb().Name);
        //        var file = Request.Files[0];
        //        var reader=new StreamReader(Request.Files[0].InputStream);
        //        string xml=reader.ReadToEnd();
        //        blog.ImportFromXml(xml);
        //        //var fileInfo = new FileInfo(file.FileName);
        //        //Web.SaveFile(file.FileName, FileUtilty.ReadStream(file.InputStream), HttpContext.Request.Url);
        //    }
        //    catch (Exception e)
        //    {
        //        HttpContext.Response.StatusCode = 424;
        //        return Content("Method Failure - " + e.Message);
        //    }

        //    HttpContext.Response.StatusCode = 201;
        //    return Content("OK");
        //}
    }
}
